package com.zry.simpleBlog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zry.simpleBlog.comment.enums.RoleEnum;
import com.zry.simpleBlog.comment.enums.RespBeanEnum;
import com.zry.simpleBlog.comment.exception.BusinessException;
import com.zry.simpleBlog.comment.respBean.RespBean;
import com.zry.simpleBlog.comment.utils.StringUtil;
import com.zry.simpleBlog.comment.utils.UserContext;
import com.zry.simpleBlog.dto.CommentDTO;
import com.zry.simpleBlog.email.EmailService;
import com.zry.simpleBlog.email.model.EmailDto;
import com.zry.simpleBlog.entity.Blog;
import com.zry.simpleBlog.entity.Comment;
import com.zry.simpleBlog.entity.User;
import com.zry.simpleBlog.mapper.BlogMapper;
import com.zry.simpleBlog.mapper.CommentMapper;
import com.zry.simpleBlog.service.ICommentService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static org.springframework.beans.BeanUtils.copyProperties;

/**
 * 评论
 *
 * @author zry
 * @since 2022-04-09
 */
@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements ICommentService {

    @Resource
    private CommentMapper commentMapper;
    @Resource
    private BlogMapper blogMapper;

    @Resource
    private EmailService emailService;

    @Value("${comment.default.avatar}")
    private String avatar;

    @Value("${init.article.guestbook.id}")
    private String guestbookId;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public RespBean saveComment(CommentDTO comment) {
        User user = UserContext.getCurrentUser();
        Blog blog = blogMapper.selectById(comment.getBlogId());
        if (blog == null) {
            throw new BusinessException(RespBeanEnum.BLOG_NOT_EXISTED);
        }
        comment.setCreatorRole(RoleEnum.VISITOR.getType());
        if (user != null) {
            comment.setAvatar(user.getAvatar());
            comment.setCreatorRole(RoleEnum.getRoleEnumByRank(user.getRank()).getType());
        }
        if (StringUtils.isEmpty(comment.getAvatar())) {
            comment.setAvatar(avatar);
        }

        if (comment.getParentComment() != null && !StringUtils.isEmpty(comment.getParentComment().getId())) {
            Comment parentComment = commentMapper.selectById(comment.getParentComment().getId());
            if (parentComment == null) {
                throw new BusinessException(RespBeanEnum.COMMENT_NOT_EXISTED);
            }
        }
        comment.setCreateTime(new Date());
        comment.setId(UUID.randomUUID().toString());
        commentMapper.insert(comment.parseComment());
        // 发送邮箱
        this.sendEmail(comment, blog);
        return RespBean.success();
    }

    private void sendEmail(CommentDTO comment, Blog blog) {
        EmailDto emailDto = new EmailDto();
        emailDto.setBlogTitle(blog.getTitle());
        emailDto.setEmailTo(comment.getParentComment().getEmail());

        // 邮件相同不发送
        if (comment.getEmail().equals(comment.getParentComment().getEmail())) {
            return;
        }

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();

        String basePath = request.getScheme() + "://" + request.getServerName() + StringUtil.COLON + request.getServerPort() + request.getContextPath();

        if (blog.getId().equals(guestbookId)) {
            basePath += "/p/guestbook.html";
        } else {
            basePath += "/p/blog.html?article=" + blog.getId();
        }

        emailDto.setUrl(basePath);
        emailDto.setContent(comment.getContent());

        emailService.sendSimpleEmail(emailDto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public RespBean removeComment(String id) {

        List<Comment> commentList = commentMapper.selectList(new QueryWrapper<Comment>().eq("parent_comment_id", id));
        if (commentList != null && !commentList.isEmpty()) {
            return RespBean.error(RespBeanEnum.DELETE_ERROR);
        }
        int i = commentMapper.deleteById(id);
        if (i != 1) {
            return RespBean.error(RespBeanEnum.DELETE_ERROR);
        }
        return RespBean.success();
    }

    /**
     * 存放迭代找出的所有子代的临时列表
     */
    private static List<CommentDTO> COMMENT_TEMP_CONTENT = new ArrayList<>();

    @Override
    public RespBean pageCommentByBlogId(Integer pageNum, Integer pageSize, String blogId) {
        //找出所有的一级评论
        Page<Comment> commentsPage = commentMapper.selectPage(new Page<>(pageNum, pageSize), new QueryWrapper<Comment>().eq("blog_id", blogId).isNull("parent_comment_id").orderByDesc("create_time"));
        Page<CommentDTO> commentDtoPage = (Page<CommentDTO>) commentsPage.convert(v -> {
            CommentDTO u = new CommentDTO();
            copyProperties(v, u);
            return u;
        });
        combineChildren(commentDtoPage);
        return RespBean.success(commentDtoPage);
    }


    private void combineChildren(Page<CommentDTO> comments) {
        List<CommentDTO> records = comments.getRecords();

        for (CommentDTO comment : records) {
            COMMENT_TEMP_CONTENT = new ArrayList<>();
            // 获取所有的二级评论
            List<CommentDTO> replyComments = commentMapper.selectReplyList(comment.getId());
            for (CommentDTO reply : replyComments) {
                COMMENT_TEMP_CONTENT.add(reply);
                // 递归，找出每一个二级评论的所有子代
                recursively(reply);
            }
            comment.setReplyComments(COMMENT_TEMP_CONTENT);
        }
    }

    /**
     * 功能描述: 因为二级评论还会有回复者所以我们要递归的查找所有二级评论的回复者
     *
     * @create 2022/5/12
     */
    private void recursively(CommentDTO comment) {
        // 顶节点添加到临时存放集合
        List<CommentDTO> commentDTOS = commentMapper.selectReplyList(comment.getId());
        // 是否存在子评论
        if (commentDTOS == null || commentDTOS.isEmpty()) {
            return;
        }
        for (CommentDTO reply : commentDTOS) {
            COMMENT_TEMP_CONTENT.add(reply);
            // 查出子级 注入父级
            recursively(reply);
        }
    }

}
